package p2p.logic.util;

import java.util.Arrays;
import java.util.UUID;

import p2p.logic.exceptions.InvalidIpException;

/**
 * 
 * Utils class provides some basic Byte operations
 * 
 */
public class Utils {

	/**
	 * 
	 * @param ip
	 * @return an 4 bytes array representing the given 32 Bit - ip
	 * @throws InvalidIpException
	 */
	public static byte[] ipToByteArray(String ip) throws InvalidIpException {
		String[] ipComponents = ip.split("\\.");

		if (ipComponents.length == 4) {

			byte[] ipArray = new byte[4];

			for (int i = 0; i < ipComponents.length; i++) {
				ipArray[i] = (byte) (Integer.valueOf(ipComponents[i]) & 0xFF);
			}

			return ipArray;

		} else {
			throw new InvalidIpException();
		}
	}

	/**
	 * 
	 * @param ipArr
	 * @return an String representation of the ip array
	 * @throws InvalidIpException
	 */
	public static String byteArrayToIp(byte[] ipArr) throws InvalidIpException {
		if (ipArr.length == 4) {
			String ip = "";
			for (byte b : ipArr) {
				ip += String.valueOf(b & 0xFF) + ".";
			}
			return ip.substring(0, ip.length() - 1);
		} else {
			throw new InvalidIpException();
		}
	}

	/**
	 * 
	 * @param number
	 * @return an byte array representing the given int number
	 */
	public static byte[] intToByteArray(int number) {
		if (number == 1)
			return new byte[]{1};
		
		double bitLength = Math.ceil(Math.log10(number) / Math.log10(2));
		double x = (int) Math.ceil(bitLength / 8);
		byte[] array = new byte[(int) x];
		
		for (int i = 0; i < x; i++) {
			array[i] = (byte) (number % (0xFF + 1));
			number = number / (0xFF + 1);
		}
		return array;

	}

	/**
	 * 
	 * @param numArray
	 * @return an intValue for the given byte array representation
	 */
	public static int byteArrayToInt(byte[] numArray) {
		int result = 0, op = 1;
		for (int i = 0; i < numArray.length; i++) {
			result += (numArray[i] & 0xFF) * op;
			op *= (0xFF + 1);
		}
		return result;
	}

	/**
	 * 
	 * @return an new UUID
	 */
	public static UUID newUUID() {
		return UUID.randomUUID();
	}

	/**
	 * 
	 * @param uuid
	 * @return an byte array representing the uuid
	 */
	public static byte[] uuidToByteArray(UUID uuid) {

		long msb = uuid.getMostSignificantBits();
		long lsb = uuid.getLeastSignificantBits();
		byte[] buffer = new byte[16];

		for (int i = 0; i < 8; i++) {
			buffer[i] = (byte) (msb >>> 8 * (7 - i));
		}
		for (int i = 8; i < 16; i++) {
			buffer[i] = (byte) (lsb >>> 8 * (7 - i));
		}

		return buffer;

	}

	/**
	 * 
	 * @param byteArray
	 * @return UUID - Object for byte Array
	 */
	public static UUID toUUID(byte[] byteArray) {

		long msb = 0;
		long lsb = 0;
		for (int i = 0; i < 8; i++)
			msb = (msb << 8) | (byteArray[i] & 0xff);
		for (int i = 8; i < 16; i++)
			lsb = (lsb << 8) | (byteArray[i] & 0xff);
		UUID result = new UUID(msb, lsb);

		return result;
	}
	
	/**
	 * @param array
	 * @return returns the subArray of the given array inclusive start and exclusive stop
	 */
	public static byte[] subArray(byte[] array, int start, int stop){
		byte[] res = Arrays.copyOfRange(array, start, stop);
		return res;
	}
	
	/**
	 * 
	 * @param result
	 * @param toCopy
	 * @param startPos
	 * @return fills the result array 
	 */
	public static byte[] insertArray(byte[] result, byte[] toCopy, int startPos){
		

		for (int i = 0; i < toCopy.length; i++){
			result[startPos] = toCopy[i];
			startPos++;
		}
		
		return result;
		
	}
	
	
}
